package com.googlecode.transmutant.spring;

import com.googlecode.transmutant.Steppable 
import org.springframework.beans.factory.annotation.Autowired 
import org.springframework.context.ApplicationContext 


class SpringStepper implements Steppable, GroovyInterceptable {
	
	StepsWrapper stepsWrapper
	
	@Autowired
    private ApplicationContext context
	
	void run() {
		def steps = stepsWrapper.createSteps()
		step(steps)
	}
	
	@Override
	public void step(Object steps) {
		Map<String,Object> outs
		for (StepWrapper step in steps) {
			step.ins = outs
			Map<String,Object> out = runStep(step)
			outs = getOuts(step)
			outs = out.plus(outs)
		}
	}
	
	Map<String,Object> runStep(StepWrapper step) {
	}
	
	Map<String,Object> getOuts(StepWrapper step) {
	}
	
	@Override
	def invokeMethod(String name, Object objs) {
		if(name.equals("runStep")) {
			StepWrapper wrapper = objs[0]
			
			Map<String,Object> ins = wrapper.ins
			if(ins != null) {
				Set<String> keys = ins.keySet()
				keys.each {key->
					def actualStep = wrapper.ref
					if(actualStep.hasProperty(key)) {
						actualStep.putAt(key, ins.get(key))
					}
				}
			}
			
			List<StepMethodWrapper> methodWrappers = wrapper.stepMethods
			Map<String,Object> outMap = new HashMap<String,Object>()
			for (StepMethodWrapper methodWrapper in methodWrappers) {
				List<Object> args = null
				if(methodWrapper.params.size != 0) {
					args = []
					for (param in methodWrapper.params) {
						if(param instanceof InParam) {
							args.add(wrapper.ins.get(param.name))
						} else {
							def ref = context.getBean(param.bean)
							args.add(ref)
						}
					}
				}
				
				def out = wrapper.ref.invokeMethod(methodWrapper.name,args)
				if(methodWrapper.out != null) {
					outMap.put(methodWrapper.out,out)
				}
			}
			return outMap
		} else if (name.equals("getOuts")) {
			StepWrapper wrapper = objs[0]
			Map<String,String> outs = wrapper.outs
			Set<String> keys = outs.keySet()
			Map<String, Object> outsMap = new HashMap<String,Object>()
			keys.each {key->
				outsMap.put(outs.get(key),wrapper.ref.getAt(key))
			}
			return outsMap
		} else {
			def metaMethod = metaClass.getMetaMethod(name, objs)
			def result = metaMethod.invoke(this, objs)
			return result
		}
	}
}